from typing import Type, Union

from selenium.webdriver import *
from selenium.webdriver.chrome.service import Service

from tools.log import logger
from setting import *


class BrowserTypeError(Exception):
    """
    自定义浏览器类型异常
    """

    def __init__(self, _type):
        self._type = _type

    def __str__(self):
        return "unsupported browser type:{}".format(self._type)


class Browser:
    # 浏览器驱动，需要根据运行环境修改路径
    CHROME_DRIVER_PATH = CHROME_DRIVER_PATH
    # 窗口大小
    WINDOWS_SIZE = WINDOWS_SIZE
    # 隐式等待时间
    IMP_TIME = IMP_TIME
    # 页面加载时间
    PAGE_LOAD_TIME = PAGE_LOAD_TIME
    # JS 执行时间
    SCRIPT_TIME_OUT = SCRIPT_TIME_OUT
    # 浏览器是否无头化
    HEADLESS = HEADLESS

    def __init__(
        self,
        browser_type: Type[Union[Firefox, Chrome, Ie, Edge, Opera]] = Chrome,
        option_type: Type[
            Union[FirefoxOptions, ChromeOptions, IeOptions]
        ] = ChromeOptions,
        driver_path: str = CHROME_DRIVER_PATH,
    ):

        if not issubclass(browser_type, (Firefox, Chrome, Ie, Edge, Opera)):
            raise BrowserTypeError(browser_type)

        if not issubclass(option_type, (FirefoxOptions, ChromeOptions, IeOptions)):
            raise BrowserTypeError(option_type)

        if not isinstance(driver_path, str):
            raise TypeError

        self._path = driver_path
        self._browser = browser_type
        self._option = option_type

    @property
    def options(self):
        """
        浏览器特定的操作，在子类中实现
        :return:
        """
        return

    @property
    def browser(self):
        """
        启动浏览器，返回浏览器示例
        :return:
        """
        return


class CHROME(Browser):
    """
    chrome 浏览器
    """

    # 用于控制 options 方法是否执行
    OPTION_MARK = CHROME_OPTION_MARK
    # 用于控制 browser 方法中的 chrome 是否添加启动参数
    METHOD_MARK = CHROME_METHOD_MARK
    # 窗口大小
    WINDOWS_SIZE = WINDOWS_SIZE
    # 隐式等待时间
    IMP_TIME = IMP_TIME
    # 页面加载时间
    PAGE_LOAD_TIME = PAGE_LOAD_TIME
    # JS 执行时间
    SCRIPT_TIME_OUT = SCRIPT_TIME_OUT
    # 浏览器是否无头化
    HEADLESS = HEADLESS
    # 启动就最大化
    START_MAX = CHROME_START_MAXIMIZED
    EXP = CHROME_EXPERIMENTAL

    @property
    def options(self):
        if self.OPTION_MARK:
            chrome_option = self._option()
            chrome_option.add_argument(self.START_MAX)

            for k, v in self.EXP.items():
                chrome_option.add_experimental_option(k, v)

            chrome_option.headless = self.HEADLESS

            return chrome_option
        return None

    @property
    def browser(self):
        # 如果 options 方法返回 None，直接生成一个 chrome 浏览器
        service = Service(self._path)
        if self.options:
            # chrome = self._browser(self._path, options=self.options)
            chrome = self._browser(options=self.options, service=service)
        else:
            # chrome = self._browser(self._path)
            chrome = self._browser(service=service)

        if self.METHOD_MARK:
            chrome.implicitly_wait(self.IMP_TIME)
            chrome.set_script_timeout(self.SCRIPT_TIME_OUT)
            chrome.set_page_load_timeout(self.PAGE_LOAD_TIME)
            # chrome.set_window_size(*self.WINDOWS_SIZE)
        logger.info("启动 Chrome 浏览器")
        return chrome


if __name__ == "__main__":
    with CHROME().browser as _chrome:
        _chrome.get("https://www.baidu.com")
        from time import sleep

        sleep(5)
